package com.focusai.efairy.network;

import com.focusai.efairy.network.exception.NetworkException;
import com.focusai.efairy.network.request.base.Request;
import com.focusai.efairy.network.utils.OkHttpUtil;
import com.focusai.efairy.utils.log.Log;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Dns;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;

/**
 * Created by heqingbao on 2016/8/3.
 */
public class OkHttpNetwork implements Network {
    private static final String TAG = OkHttpNetwork.class.getSimpleName();

    private OkHttpClient mHttpClient;
    private String mUserAgent;

    public OkHttpNetwork(final HttpDns httpDns, List<Interceptor> interceptors, List<Interceptor> networkInterceptors, String userAgent) {

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS);//.retryOnConnectionFailure(true);

        // add application interceptor
        if (interceptors != null && !interceptors.isEmpty()) {
            for (Interceptor interceptor : interceptors) {
                builder.addInterceptor(interceptor);
            }
        }

        // add network interceptor
        if (networkInterceptors != null && !networkInterceptors.isEmpty()) {
            for (Interceptor interceptor : networkInterceptors) {
                builder.addNetworkInterceptor(interceptor);
            }
        }

        if (httpDns != null) {
            builder.dns(new Dns() {
                @Override
                public List<InetAddress> lookup(String hostname) throws UnknownHostException {
                    return httpDns.lookup(hostname);
                }
            });
        }
        mHttpClient = builder.build();
        mUserAgent = userAgent;
    }

    @Override
    public NetworkResponse performRequest(Request<?> request) throws NetworkException {
        okhttp3.Response resp;
        try {
            okhttp3.Request req = OkHttpUtil.createRequest(request, mUserAgent);
            resp = mHttpClient.newCall(req).execute();
            return createNetworkResponse(resp);
        } catch (Exception e) {
            throw new WrapperException(e).unwrap();
        }
    }

    @Override
    public long sendRequest(Request<?> request, final NetCallback callback) {
        try {
            okhttp3.Request req = OkHttpUtil.createRequest(request, mUserAgent);
            mHttpClient.newCall(req).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.E(TAG,"Send request failure:" + call.request().url(), e);
                    callback.onError(new WrapperException(e).unwrap());
                }

                @Override
                public void onResponse(Call call, okhttp3.Response response) throws IOException {
                    Log.I(TAG,"Send request success:" + call.request().url());
                    try {
                        NetworkResponse networkResponse = createNetworkResponse(response);
                        callback.onResponse(networkResponse);
                    } catch (Exception e) {
                        callback.onError(new WrapperException(e).unwrap());
                    }
                }
            });

            return (long) req.tag();
        } catch (Exception e) {
            Log.E(TAG,"Send request error:" + request.getUrl(), e);
            callback.onError(new NetworkException(e));
        }

        return -1;
    }

    @Override
    public void cancelRequest(long requestId) {
        if (requestId < 0) {
            return;
        }

        Long objId = requestId;
        for (Call call : mHttpClient.dispatcher().queuedCalls()) {
            if (objId.equals(call.request().tag())) {
                call.cancel();
            }
        }

        for (Call call : mHttpClient.dispatcher().runningCalls()) {
            if (objId.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    private NetworkResponse createNetworkResponse(okhttp3.Response response) throws IOException {
        Map<String, String> headers = new HashMap<>();
        Headers hs = response.headers();
        for (String name : hs.names()) {
            headers.put(name, response.header(name));
        }

        return new NetworkResponse(response.code(), response.body().byteStream(), headers,response.receivedResponseAtMillis());
    }

//    private Cache createCache(){
//        File cacheFile =  new File(KdweiboApplication.getContext().getExternalCacheDir().toString(),"cache");
//        int cacheSize = 10 * 1024 *1024;
//        return new Cache(cacheFile,cacheSize);
//    }
}
